package edu.ncsu.csc;

import java.io.IOException;
import java.util.TimerTask;

import javax.microedition.io.Datagram;

import com.sun.spot.util.Queue;

import edu.ncsu.csc.sensors.Sensor;

/**
 * A TimerTask that handles the readings of a single sensor. Whenever this task is run, it reads in a single value from its
 * associated Sensor and adds it to a Datagram. When the Datagram becomes full, this class submits the Datagram to a Queue
 * specified in its constructor, which should be processed by some other class that is responsible for radio packet transmission
 * 
 * @author David A. Boyuka, II
 */
public class SensorTask extends TimerTask {
	private static final int NUM_SAMPLES_PER_PACKET = 15;

	private Sensor sensor;
	private byte sensorID;
	private DatagramFactory dgFactory;
	private Queue dgQueue;

	private Datagram dg;
	private int numSamplesInDG;
	private long lastSampleTime;

	/**
	 * @param sensor the sensor from which to read
	 * @param sensorID the sensor ID to include in the Datagrams this class produces
	 * @param dgFactory a factory that this object can request new Datagrams from
	 * @param dgQueue the Queue to which this object should submit filled Datagrams to be transmitted
	 */
	public SensorTask(Sensor sensor, byte sensorID, DatagramFactory dgFactory, Queue dgQueue) {
		this.sensor = sensor;
		this.sensorID = sensorID;
		this.dgFactory = dgFactory;
		this.dgQueue = dgQueue;

		prepareDatagram();
	}

	/**
	 * Get a new Datagram from the DatagramFactory provided to this object, reset it and write the sensor ID to it. Also reset
	 * state variables.
	 */
	private void prepareDatagram() {
		numSamplesInDG = 0;
		lastSampleTime = -1;

		dg = dgFactory.newDatagram();

		try {
			dg.reset();
			dg.writeByte(sensorID);
		} catch (IOException ioe) {
			System.out.println("Error creating new datagram in SensorTask for sensor with ID = " + sensorID);
			ioe.printStackTrace();
		}
	}

	/**
	 * This is the method called by Timer when this task is scheduled.
	 */
	public void run() {
		addSampleToDatagram((short)sensor.getValue());
	}

	/**
	 * Adds a given reading to the end of the Datagram. Submits the Datagram to the Queue and gets
	 * a new one if it becomes full.
	 * 
	 * @param val the sensor reading to append
	 */
	private void addSampleToDatagram(short val) {
		long time = System.currentTimeMillis();

		try {
			if (lastSampleTime == -1) dg.writeLong(time);
			else					  dg.writeShort((short)(time - lastSampleTime));

			dg.writeShort(val);

			lastSampleTime = time;
			numSamplesInDG++;
		} catch (IOException ioe) {
			System.out.println("Error adding new sample to datagram in SensorTask for sensor with ID = " + sensorID);
			ioe.printStackTrace();
		}

		if (numSamplesInDG >= NUM_SAMPLES_PER_PACKET) commitDatagram();
	}

	/**
	 * Submits the current Datagram to the Queue, and prepares a new one.
	 */
	private void commitDatagram() {
		dgQueue.put(dg);
		prepareDatagram();
	}
}
